﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ZFBActivation.ThreadPool
{
	/// <summary>
	/// 线程操作类,实现的DoWork方法中必须捕捉异常
	/// </summary>
	public abstract class DThread : IDisposable
	{
		#region < 构造 >
		/// <summary>
		/// 构造函数
		/// </summary>
		protected DThread() {
			_IsRunning = true;
			_Sem = new SemaphoreSlim(0, 1);
			//启动一个一直等待的线程
			_Thread = new Thread(ThreadWork);
			_Thread.IsBackground = true;
			_Thread.Start();
		}
		#endregion

		#region < 变量 >
		//内部线程
		protected Thread _Thread;
		//运行标识
		protected bool _IsRunning;
		//信号量
		protected SemaphoreSlim _Sem;
		#endregion

		#region < 自定义事件 >
		/// <summary>
		/// 归还线程事件
		/// </summary>
		internal event EventHandler ThreadGiveBack;
		private void OnThreadGiveBack() {
			if (ThreadGiveBack != null)
				ThreadGiveBack(this, EventArgs.Empty);
		}
		#endregion

		#region < 方法 >
		/// <summary>
		/// 运行线程
		/// </summary>
		public void Run() {
			_Sem.Release();
		}

		//线程启动,创建之后便一直运行
		[SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
		private async void ThreadWork() {
			try {
				while (_IsRunning) {
					if(_Sem != null) {
						_Sem.Wait();
					}
	
					await DoWork();
					OnThreadGiveBack();
				}
			} catch (ThreadAbortException) {
				Thread.ResetAbort();
			} catch (Exception ex) {
				throw new Exception("子线程必须捕捉异常", ex);
			}
		}

		/// <summary>
		/// 线程工作方法,根据具体需要在继承的类中重载
		/// </summary>
		protected abstract ValueTask  DoWork();
		#endregion

		#region < IDisposable 成员 >
		/// <summary>
		/// 释放资源
		/// </summary>
		/// <param name="disposing">为true则释放托管资源和非托管资源,为false则仅释放非托管资源.</param>
		protected virtual void Dispose(bool disposing) {
			if (_Thread != null) {
				try { _Thread.Abort(); } catch { }
				_Thread = null;
			}

			if (_Sem != null) {
				_Sem.Dispose();
				_Sem = null;
			}
		}

		/// <summary>
		/// 释放资源
		/// </summary>
		public void Dispose() {
			Dispose(true);
			GC.SuppressFinalize(this);
		}
		#endregion
	}
}
